#ifndef _SCHED_H
#define _SCHED_H

#include <linux/head.h>
#include <linux/fs.h>
#include <signal.h>
#include <sys/param.h>
#include <sys/resource.h>

#define NR_TASKS	64

extern void sched_init(void);
extern void schedule(void);
extern void trap_init(void);

typedef int (*fn_ptr)();

struct i387_struct {
	long	cwd;
	long	swd;
	long	twd;
	long	fip;
	long	fcs;
	long	foo;
	long	fos;
	long	st_space[20];	/* 8*10 bytes for each FP-reg = 80 bytes */
};

struct tss_struct {
	long	back_link;	/* 16 high bits zero */
	long	esp0;
	long	ss0;		/* 16 high bits zero */
	long	esp1;
	long	ss1;		/* 16 high bits zero */
	long	esp2;
	long	ss2;		/* 16 high bits zero */
	long	cr3;
	long	eip;
	long	eflags;
	long	eax,ecx,edx,ebx;
	long	esp;
	long	ebp;
	long	esi;
	long	edi;
	long	es;		/* 16 high bits zero */
	long	cs;		/* 16 high bits zero */
	long	ss;		/* 16 high bits zero */
	long	ds;		/* 16 high bits zero */
	long	fs;		/* 16 high bits zero */
	long	gs;		/* 16 high bits zero */
	long	ldt;		/* 16 high bits zero */
	long	trace_bitmap;	/* bits: trace 0, bitmap 16-31 */
	struct i387_struct i387;
};

struct task_struct {
/* these are hardcoded - don't touch */
	/* 任务状态：-1表示不可运行，0表示可运行，> 0 表示停止 */
	long state;	/* -1 unrunnable, 0 runnable, >0 stopped */
	/* 计数：任务运行的时间片 */
	long counter;
	/* 任务优先级 */
	long priority;
	/* 信号 */
	long signal;
	/* 信号处理结构体，包含注册的信号处理函数等 */
	struct sigaction sigaction[32];
	/* 信号阻塞位图 */
	long blocked;	/* bitmap of masked signals */
/* various fields */
	/* 退出码 */
	int exit_code;
	/* 代码段起始位置，代码段结束位置，数据段结束位置，brk堆分配位置，栈起始位置 */
	unsigned long start_code,end_code,end_data,brk,start_stack;
	/* 进程id，进程组id，会话id，进程组领导id */
	long pid,pgrp,session,leader;
	/* 分组。每个用户最多归属分组 NGROUPS */
	int	groups[NGROUPS];
	/* 
	 * pointers to parent process, youngest child, younger sibling,
	 * older sibling, respectively.  (p->father can be replaced with 
	 * p->p_pptr->pid)
	 */
	/**
	 * p_pptr --- 指向父任务指针 (p->father 可以使用 p->p_pptr->pid 替代)
	 * p_cptr --- 指向最年轻的子任务
	 * p_ysptr --- 指向下一个被创建的兄弟任务
	 * p_osptr --- 指向上一个被创建的兄弟任务
	 */
	struct task_struct	*p_pptr, *p_cptr, *p_ysptr, *p_osptr;
	/* 用户id，有效用户id，超级用户id */
	unsigned short uid,euid,suid;
	/* 组id，有效组id，超级组id */
	unsigned short gid,egid,sgid;
	/* 超时时间，告警 */
	unsigned long timeout,alarm;
	/* 时间相关的定义 */
	long utime,stime,cutime,cstime,start_time;
	/* 这个定义是啥意思？？？ */
	struct rlimit rlim[RLIM_NLIMITS]; 
	/* 进程标志 */
	unsigned int flags;	/* per process flags, defined below */
	unsigned short used_math;
/* file system info */
	/* 文件系统相关信息 */
	/* tty */
	int tty;		/* -1 if no tty, so it must be signed */
	unsigned short umask;
	/* 文件节点指针：当前路径，根路径，可执行文件路径，库文件路径 */
	struct m_inode * pwd;
	struct m_inode * root;
	struct m_inode * executable;
	struct m_inode * library;
	unsigned long close_on_exec;
	struct file * filp[NR_OPEN]; /* 打开的文件描述符列表 */
/* ldt for this task 0 - zero 1 - cs 2 - ds&ss */
	/* 任务对应的ldt表，包括三个描述符：0保留不用，1是代码段，2是数据段和堆栈段 */
	struct desc_struct ldt[3];
/* tss for this task */
	/* 任务对应的tss结构,为何放在结构体定义的最后一项，也是有讲究的 */
	struct tss_struct tss;
};

/*
 * INIT_TASK 用于设置第一个任务（task0），基地址=0，段限长=640KB（0x9ffff）
 *
 * LDT结构
 * 	* ldt 三个段描述符，第一个保留
	* 第二个是代码段（32位可读可执行代码段，基地址0，段限长为640KByte）
	* 代码段：00c0fa00 0000009f ：G=1（4K颗粒度），D=1（32位），P=1（段在内存中存在）
	* 							DPL=3（用户态），S=1（代码段），TYPE=0b1010（可读可执行），段限长（160 * 4K颗粒度）
	* 		
	* 第三个是数据段（32位可读可写数据段，基地址0，段限长为640KByte）					
	* 数据段：00c0f200 0000009f : G=1（4K颗粒度），D=1（32位），P=1（段在内存中存在）
	* 							DPL=3（用户态），S=1（数据段），TYPE=0b0010（可读可写），段限长（160 * 4K颗粒度）
 *
 * tss结构
	* 前一个任务链接为0，esp0（任务内核态的栈顶）指向 任务0 数据结构末尾（实际就是4096字节的末尾，刚好是一个页的末尾）
	* ss0 = 0x10，指向的是内核态的数据段选择符（很容易理解，进入内核态执行，堆栈也是要内核态段）
	* cr3 = &pg_dir 指向的地址，也就是页表目录基地址，在 head.s 中定义，实际上就是从物理地址0开始的
	* es cs ss ds fs gs 都为 0x17，为 LDT 中的数据段选择符（为何这里的CS段也是使用 0x17 呢）
	* ldt 段选择符使用 _LDT 宏，通过任务编号获得
	* I/O 位图基地址为 0x80000000 ， 基地址是0x8000
 */
#define INIT_TASK \
	/* 初始化任务可运行，计数15，优先级15 */ { 0,15,15, \
	/* 初始化注册信号无， 信号处理结构体为空，信号阻塞位图为0（表示不阻塞任何信号） */ 0,{{},},0, \
	/* 退出码0，所有段的位置都是从0开始（brk对于任务0没有意义） */ 0,0,0,0,0,0, \
	/* 各种进程id都是0 */ 0,0,0,0, \
	/* 没有归属于任何分组 */ {NOGROUP,}, \
	/* 父任务指向自身，其他兄弟和子任务当前没有置为0 */ &init_task.task,0,0,0, \
	/* 用户id相关值都是0 */ 0,0,0,0,0,0, \
	/* 时间相关的定义都是0 */ 0,0,0,0,0,0,0, \
	/* 表示各种资源的当前使用值和最大限制值，放开到最大 */ { {0x7fffffff, 0x7fffffff}, {0x7fffffff, 0x7fffffff},  \
		  {0x7fffffff, 0x7fffffff}, {0x7fffffff, 0x7fffffff}, \
		  {0x7fffffff, 0x7fffffff}, {0x7fffffff, 0x7fffffff}}, \
	/* 进程标志为0 */ 0, \
	/* 是否使用数学协处理器??? */ 0, \
	/* tty为-1，用户权限掩码是0022，文件指针节点都置为空 */ -1,0022,NULL,NULL,NULL,NULL,0, \
	/* 文件打开列表：初始化未打开任何文件 */ {NULL,}, \
	{ \
		{0,0}, \
		/* code:base=0,limit=640k  */ {0x9f,0xc0fa00}, \
		/* data:base=0,limit=640k */ {0x9f,0xc0f200}, \
	}, \
	{0,PAGE_SIZE+(long)&init_task,0x10,0,0,0,0,(long)&pg_dir,\
	 0,0,0,0,0,0,0,0, \
	 /* 段选择符都是0x17，指向 ldt 代码段 */ 0,0,0x17,0x17,0x17,0x17,0x17,0x17, \
	 _LDT(0),0x80000000, \
		{} \
	}, \
}

extern struct task_struct *task[NR_TASKS];
extern struct task_struct *last_task_used_math;
extern struct task_struct *current;
extern unsigned long volatile jiffies;


/* 第一个任务的 tss 索引，前面0-3个给了内核 */
#define FIRST_TSS_ENTRY 4
#define FIRST_LDT_ENTRY (FIRST_TSS_ENTRY+1) /* 紧接着在 tss 后面 */
#define _TSS(n) ((((unsigned long) n)<<4)+(FIRST_TSS_ENTRY<<3))
#define _LDT(n) ((((unsigned long) n)<<4)+(FIRST_LDT_ENTRY<<3))
#define ltr(n) __asm__("ltr %%ax"::"a" (_TSS(n)))
#define lldt(n) __asm__("lldt %%ax"::"a" (_LDT(n)))

#endif /* _SCHED_H */